import { action, makeAutoObservable, reaction, toJS } from "mobx";
import { persist } from "mobx-persist";
import i18n from "i18n-js";
import isEqual from "lodash/isEqual";
import global from "@/utils/global";
import { getDeviceList } from "@/services/gizwitsSdk";
import SDK from "@/utils/SDK";
import {
  getUserDeviceList,
  unbindDeviceByMac,
  editDeviceName,
  hideDevices,
} from "@/services/aepDeviceApi";
import ProductConfig, {
  getProductName,
  getItemForPk,
  isThirdCloud,
  IProduct,
  isBLEBroadCast,
  isBLE,
} from "@/config/product";
import { trim, isSameDevice, getDeviceId } from "@/utils";
import Toast from "@/utils/Toast";
import GStatistics, { GStatisticsEvent } from "@/utils/GStatistics";
import language from "../language";
import deviceDetailModel from "../deviceDetail";
import deviceDataModel from "../deviceData";
import {
  CapacityState,
  ConnectState, deviceIsInConnecting, getDeviceCapacities, IConnectStateMap,
  INewDevice, isDeviceCapacityChange,
  updateBleCapacityState, updateDeviceBybleConnectStateMap, updateWifiCapacityState
} from './deviceCapacity';
import Queue from "./queue";


export function deviceDefaultName(device: IDevice, languageData: any) {
  let productName = getProductName(device.productKey, languageData.key);
  if (device.mac) {
    const length = device.mac.length;
    productName = `${productName}-${device.mac.substring(length - 4, length)}`;
  }
  return productName;
}

function mergeDevice(
  sdkDevice: any,
  serviceDevice: IDevice,
  languageData: any
) {
  sdkDevice.sno = serviceDevice.sno;
  sdkDevice.hide = serviceDevice.hide; // 同步显示或者隐藏
  sdkDevice.roomId = serviceDevice.roomId; // 同步显示或者隐藏
  sdkDevice.manufacturer = serviceDevice.manufacturer; // 同步第三标志
  // 名称需要综合起来判断
  const info = getItemForPk(sdkDevice.productKey) as IProduct;
  const deviceName =
    trim(serviceDevice.name) || deviceDefaultName(sdkDevice, languageData);
  sdkDevice.alias = deviceName;
  sdkDevice.name = deviceName;
  sdkDevice.deviceSourceType = serviceDevice.deviceSourceType;
  if (info) {
    sdkDevice.gid = info.gid;
  }
}

const meargeList = (sdkDevices: IDevice[], serverDevices: IDevice[]) => {
  sdkDevices.map((sdkDevice) => {
    serverDevices.find((serviceDevice) => {
      if (isSameDevice(serviceDevice, sdkDevice)) {
        mergeDevice(sdkDevice, serviceDevice, language);
        return true;
      }
      return false;
    });
  });
};

/**
 * 所有插入的设备或者更新的设备
 * 都是需要经过这个coverDevice方法
 * @param {*item}
 */
const coverDevice = (item: IDevice) => {
  const newItem = { ...item };
  // 从配置文件获取产品名称
  const name = getProductName(item.productKey, language.key);
  // eslint-disable-next-line no-multi-assign
  newItem.name = newItem.alias = name;
  newItem.onlineStatus = !!(newItem.netStatus === 1 || newItem.netStatus === 2);
  if (newItem.isLowPower && newItem.isDormant) {
    newItem.isOnline = true;
    newItem.netStatus = 2;
  }
  return newItem;
};

const coverBleDevice = (item: IDevice) => {
  const newItem = { ...item };
  // 从配置文件获取产品名称
  const name = getProductName(item.productKey, language.key);
  newItem.name = name;
  newItem.alias = name;
  return newItem;
};

/**
 * 请求Aep的设备
 * 和site的设备
 */
const getDeviceListMerge = () => {
  const promises = [getDeviceList(), getUserDeviceList()];
  return Promise.all(promises as Iterable<any>);
};

// 记录中间态的数组，主要是蓝牙连接中与断开连接中的状态,deviceId作为key，连接状态为值
let bleConnectStateMap: IConnectStateMap = {};

/**
 * 数据比对需要用到
 */
let comparing = false;
let compareStack: any = [];

let lockGetDeviceList = false;

interface IUnbindDeviceMap {
  [deviceId: string]: any;
}


// 设备解绑记录
const unbindDeviceMap: IUnbindDeviceMap = {};

class DeviceList {
  @persist("list") data: INewDevice[] = [];

  @persist("list") sdkDeviceList: IDevice[] = [];

  @persist("list") serviceDeviceList: IDevice[] = [];

  sdkBleDevices: IDevice[] = []; // 记录蓝牙设备

  // 记录选中的设备
  timer: any;

  constructor() {
    makeAutoObservable(this);
  }

  @action.bound
  async getDeviceList(forced = false) {
    if (lockGetDeviceList && !forced) return;
    lockGetDeviceList = true;
    const data = await getUserDeviceList();
    lockGetDeviceList = false;
    if (data.success) {
      console.log('getDeviceListgetDeviceListgetDeviceList', data.data.data)
      const serviceDeviceList = [...data.data.data].filter(item => getItemForPk(item.product_key))
      this.compareDeviceList({
        sdkDeviceList: [],
        serviceDeviceList
      });
      return {
        success: true,
        data: serviceDeviceList || [],
      }
    } else {
      return {
        success: false,
        data: [],
      }
    }
  }

  @action.bound
  async compareDeviceList({
    sdkDeviceList,
    serviceDeviceList,
    bleDeviceList,
  }: {
    sdkDeviceList?: IDevice[];
    serviceDeviceList?: IDevice[];
    bleDeviceList?: IDevice[];
  }) {
    // console.log('compareDeviceList', sdkDeviceList, serviceDeviceList, bleDeviceList);
    const deviceListState = this;
    // if (comparing === true) {
    //   // 上一次更新还没完成，就已经又有下一次更新，需要缓存起来
    //   compareStack.push({
    //     sdkDeviceList,
    //     serviceDeviceList,
    //     bleDeviceList,
    //   });
    //   console.log("还未完成更新，就收到下一次更新，缓存到栈里面");
    //   return;
    // }

    comparing = true;

    // 先处理sdk的wifi与蓝牙列表，取合集（因为如果是没有网络的情况，sdk的wifi列表是空的，蓝牙列表仍旧可能有值）
    // let newSdkDeviceList = [
    //   ...toJS(sdkDeviceList || deviceListState.sdkDeviceList || []),
    // ].filter((i) => ProductConfig.productKeys.includes(i.productKey));

    // newSdkDeviceList = newSdkDeviceList.map((item: IDevice) => {
    //   return { ...item, isBleOnline: false, isBlueLocal: false };
    // });


    // console.log('compare sdkdevices', newSdkDeviceList);

    // 比较sdk和服务器设备列表
    const newPayload: any = {};

    let newServiceDeviceList = serviceDeviceList
    console.log('newServiceDeviceList', newServiceDeviceList)

    newServiceDeviceList = newServiceDeviceList?.map(item => {
      return {
        ...item,
        productKey: item.product_key,
        isOnline: item.is_online,
        wifiCapacity: { state: 4 },
      }
    })

    newPayload.serviceDeviceList = newServiceDeviceList;
    newPayload.data = newServiceDeviceList
    // newPayload.data = newSdkDeviceList.filter(
    //   (d) => d.sno !== undefined && d.hide !== true
    // );
    this.setServiceDeviceList(newPayload.serviceDeviceList);
    this.setData(newPayload.data);
    comparing = false;
    if (compareStack && compareStack.length > 0) {
      // 栈里面还有数据，使用最后面的数据更新，置空栈
      console.log("栈里面还有数据，使用最后面数据更新");
      const lastestPayload = compareStack[compareStack.length - 1];
      compareStack = [];
      this.compareDeviceList(lastestPayload);
    }
  }

  /**
   * 延迟更新
   */
  @action
  updateNetStatus(payload: IDevice) {
    const { netStatus, isBlueLocal } = payload;
    if (isBlueLocal) {
      // 更新蓝牙列表
      const bleDeviceIndex = this.sdkBleDevices.findIndex((i) => isSameDevice(i, payload));
      if (bleDeviceIndex > -1) {
        const bleDevice = { ...this.sdkBleDevices[bleDeviceIndex] };
        bleDevice.netStatus = netStatus;
        this.sdkBleDevices.splice(bleDeviceIndex, 1, bleDevice);
      }
      // console.log('this.sdkBleDevices', this.sdkBleDevices);
    } else {
      // 更新wifi列表
      const wifiDeviceIndex = this.sdkDeviceList.findIndex((i) => isSameDevice(i, payload));
      if (wifiDeviceIndex > -1) {
        const wifiDevice = { ...this.sdkDeviceList[wifiDeviceIndex] };
        wifiDevice.netStatus = netStatus;
        this.sdkDeviceList.splice(wifiDeviceIndex, 1, wifiDevice);
      }
    }

    // console.log('updateNetStatus', netStatus, payload);
    const targetIndex = this.data.findIndex((item) => isSameDevice(item, payload));
    if (targetIndex > -1) {
      const wifiDevice = this.sdkDeviceList.find((i) => isSameDevice(i, payload));
      const bleDevice = this.sdkBleDevices.find((i) => isSameDevice(i, payload));
      let newDevice: INewDevice | undefined;
      if (isBlueLocal) {
        // 代表是蓝牙的
        if (bleDevice) {
          newDevice = getDeviceCapacities({
            wifiDevice,
            bleDevice: { ...bleDevice, netStatus },
            bleConnectStateMap
          });
        }
      } else if (wifiDevice) {
        newDevice = getDeviceCapacities({
          wifiDevice: { ...wifiDevice, netStatus },
          bleDevice,
          bleConnectStateMap
        });
      }
      // console.log('updateNetStatus getDeviceCapacities', newDevice);
      if (newDevice) {
        const newList = [...this.data];
        const existItem = newList[targetIndex];
        // 能力有变化才更新
        // console.log('updateNetStatus isDeviceCapacityChange', isDeviceCapacityChange(existItem, newDevice));
        if (isDeviceCapacityChange(existItem, newDevice)) {
          const item = { ...existItem, ...newDevice };
          this.data.splice(targetIndex, 1, item);
          // console.log('updateNetStatus update');
        }
      }
    }
  }

  @action
  updateName(payload: { name: string; mac: string; productKey: string }) {
    const { name } = payload;
    this.data.map((item, index) => {
      if (isSameDevice(item, payload)) {
        this.data[index].name = name;
        this.data[index].alias = name;
      }
    });
    this.data = toJS(this.data);
  }

  @action
  async unbindDevice({ device, homeId }: { device: IDevice; homeId: number }) {
    console.log('unbindDevice', device, homeId);
    const deviceId = getDeviceId(device);
    unbindDeviceMap[deviceId] = 1;
    const productConfig = getItemForPk(device.productKey);
    if (productConfig && isThirdCloud(productConfig)) {
      const res = await this.unbindThirdDevice(device);
      delete unbindDeviceMap[deviceId];
      return res;
    }

    console.log('设备需要断开连接吗？', device.isBlueLocal, device.netStatus);
    if (device.isBlueLocal && device.netStatus === 2) {
      // 断开蓝牙连接
      await this.disconnectBleDevice(device);
    }

    const data = await unbindDeviceByMac({ ...device, homeId });

    if (!data.success) {
      Toast.error(i18n.t("DELETE_FAILED"));
      delete unbindDeviceMap[deviceId];
    } else {
      // 重新查询列表
      this.getDeviceList().then(() => {
        delete unbindDeviceMap[deviceId];
      });
    }
    return data;
  }

  // 第三方设备解绑方法
  @action
  async unbindThirdDevice(device: IDevice) {
    const data = await hideDevices({
      snos: [device.sno as string],
      hide: true,
    });
    if (!data.success) {
      Toast.error(i18n.t("DELETE_FAILED"));
    } else {
      // 重新查询列表
      this.getDeviceList();
    }
    return data;
  }

  @action.bound
  setSdkDeviceList(data: IDevice[]) {
    /**
     * 转换数据
     */
    // console.log('setSdkDeviceList', data);
    const bindDeviceList = data.filter((item) => {
      return item.isBind === true;
    });

    /**
     * 同时直接更新data里面对netstatus
     * 因为sdk返回对netStatus是可靠的
     */
    bindDeviceList.map((item) => {
      if (item) {
        this.updateNetStatus(item);
      }
    });

    const dataList = bindDeviceList.map((item) => {
      return coverDevice(item);
    });
    this.sdkDeviceList = dataList;
    /**
     * token 不存在的时候，不需要比较
     */
    // if (global.token) {
    //   this.compareDeviceList({ sdkDeviceList: this.sdkDeviceList });
    // }
  }

  getDeviceListAfter2s() {
    if (this.timer) {
      clearTimeout(this.timer);
    }
    this.timer = setTimeout(() => {
      getDeviceList();
    }, 2000);
  }

  @action.bound
  setServiceDeviceList(data: IDevice[]) {
    // console.log('setServiceDeviceList', data);
    this.serviceDeviceList = data;
  }

  // 外部调用，预留给后期看需不需要触发 compareDeviceList
  @action
  updateServiceDeviceList(data: IDevice[]) {
    // console.log('updateServiceDeviceList');
    this.serviceDeviceList = data;
  }

  @action.bound
  setData(data: IDevice[] = []) {
    if (!isEqual(data, this.data.slice())) {
      // this.data = data; // 会导致监听data实例更新事件失效，如控制页监听不到网关子设备列表的变化
      // 移除不在新data中的device
      this.data.forEach((item, index) => {
        const existItem = data.find((d) => isSameDevice(d, item));
        if (!existItem) {
          // 不存在则删除
          this.data.splice(index, 1);
        } else {
          // 存在就更新
          this.data.splice(index, 1, existItem);
        }
      });
      // 插入不在旧data中的device
      data.forEach((item) => {
        if (!this.data.find((d) => isSameDevice(d, item))) {
          this.data.push(item);
        }
      });
      this.data = this.data.map((d) => {
        d.deviceId = getDeviceId(d);
        return d;
      });
      console.log('this.data', this.data);
    } else {
      console.log("setData 一致");
    }
  }

  @action.bound
  setDeviceSubscribe(device: IDevice, force: boolean) {
    if (device.isSubscribed && !force) return;
    // console.log('setDeviceSubscribe', global.token, device.isSubscribed, force,);
    const productItem = getItemForPk(device.productKey);
    if (!productItem) return;
    const newDevice = {
      ...device,
      mac: device.mac,
      did: device.did,
      productSecret: productItem.productSecret,
      productKey: device.productKey,
      isSubscribed: device.isSubscribed,
      force,
    } as any;
    if (isThirdCloud(productItem)) {
      // 第三方设备先不处理
    } else {
      Queue.push(newDevice, (sDevice: IDevice, result: any) => {
        // 处理回调，订阅成功了，把设备提前设置成已经订阅
        if (result && result.isSuccess) {
          this.data.map((item: IDevice, index: number) => {
            if (item.did === sDevice.did) {
              this.data[index].isSubscribed = true;
            }
          });
        } else {
          // 订阅不成功
        }
      });
    }
  }

  @action
  async renameDevice({ device, name }: { device: IDevice; name: string }) {
    const data = await editDeviceName({ remark: "", ...device, name });
    if (!data.success) {
      Toast.error(i18n.t("RENAME_FAILURE"));
    } else {
      this.updateName({ mac: device.mac, productKey: device.productKey, name });
    }
    return data;
  }

  @action.bound
  async setDeviceRemark({ device, remark }: any) {
    const data = await editDeviceName({ ...device, remark: JSON.stringify(remark) });
    // const data = await updateDeviceRemark({ did: device.did, remark });
    if (!data.success) {
      Toast.error(i18n.t('CAN_T_EDIT_DEVICE'));
    } else {
      this.updateRemark({ mac: device.mac, productKey: device.productKey, remark });
    }
    return data;
  }

  @action
  updateRemark(payload: { remark: {}; mac: string; productKey: string }) {
    const { remark } = payload;
    this.data.slice().map((item, index) => {
      if (isSameDevice(item, payload)) {
        this.data[index].aepRemark = remark;
      }
    });
  }

  getDeviceRemarkBySno(sno: string) {
    const target = this.data.find((device) => device.sno === sno) || {
      aepRemark: "",
      remark: "",
    };
    return target.aepRemark || target.remark;
  }

  @action.bound
  setBleDeviceList(data: IDevice[]) {
    // console.log("setBleDeviceList", data);
    // 过滤掉没有pk或者mac的蓝牙设备
    const newData = data.filter((i) => i.productKey && i.mac && !!getItemForPk(i.productKey));
    if (!isEqual(newData.slice(), this.sdkBleDevices.slice())) {
      // console.log('setBLEData', data.slice(), this.sdkBleDevices.slice());
      // 记录sdk回调的蓝牙列表
      this.sdkBleDevices = newData.slice();
      // this.sdkBleDevices = data.map((i) => {
      //   let netStatus = i.isBleOnline == true ? 1 : 0;
      //   if (i.isBleOnline) {
      //     const config = getItemForPk(i.productKey);
      //     if (isBLEConnect(config)) {
      //       // 蓝牙连接，那就设备连接类型是BLE才是可控
      //       if (deviceIsBleConnect(i)) {
      //         netStatus = 2;
      //       }
      //     } else if (isBLEBroadCast(config)) {
      //       if (deviceIsBleBroadCast(i)) {
      //         netStatus = 2;
      //       }
      //     }
      //   }
      //   return { ...i, netStatus };
      // });
      console.log("setBLEData", this.sdkBleDevices);
      // this.compareDeviceList({
      //   sdkDeviceList: this.sdkDeviceList,
      //   bleDeviceList: this.sdkBleDevices,
      // });
    }
  }

  updateBleConnectState({ device, state, connectSuccess }: { device: IDevice, state?: ConnectState, connectSuccess?: boolean }) {
    if (state !== undefined) {
      bleConnectStateMap[getDeviceId(device)] = state;
    } else {
      delete bleConnectStateMap[getDeviceId(device)];
    }
    // console.log('updateBleConnectState', bleConnectStateMap, state, device.mac);
    const targetIndex = this.data.findIndex((item) => isSameDevice(item, device));
    if (targetIndex > -1) {
      const existItem = {
        ...this.data[targetIndex],
      };
      // 由于连接成功，到实际sdk推送设备列表可能会出现时间差异，这里先预设这个设备的连接状态是BLE
      if (connectSuccess) {
        console.log("预设设备连接为BLE")
        existItem.connectType = 'BLE';
      }
      // 先校准能力state到正常状态
      if (existItem.bleCapacity) {
        existItem.bleCapacity = { ...existItem.bleCapacity }
        updateBleCapacityState(existItem.bleCapacity);
      }
      if (existItem.wifiCapacity) {
        existItem.wifiCapacity = { ...existItem.wifiCapacity }
        updateWifiCapacityState(existItem.wifiCapacity);
      }
      updateDeviceBybleConnectStateMap({ device: existItem, bleConnectStateMap });
      this.data.splice(targetIndex, 1, existItem);
    }
  }

  @action.bound
  async connectBleDevice(device: IDevice) {
    const targetDevice = this.sdkBleDevices.find((d: IDevice) =>
      isSameDevice(d, device)
    );
    if (targetDevice) {
      this.updateBleConnectState({ device, state: ConnectState.connecting });
      const res = await SDK.connectBleDevice(targetDevice);
      const isSuccess = !!(res && res.success);
      console.log("蓝牙连接", res);
      const bleEvent = new GStatisticsEvent.BleDeviceConnectEvent({
        extra: {
          product_key: device.productKey,
          connect_success: isSuccess,
          connect_result: JSON.stringify(res),
        },
      });
      GStatistics.postCalculateEvent(bleEvent);
      if (isSuccess) {
        console.log("蓝牙连接成功");
        await SDK.getBoundDevices();
        SDK.getDeviceStatus({ device })
      } else {
        /**
         * 把蓝牙能力设置回在线
         * 折中处理，让能力弹窗正常工作
         */
        device.netStatus = 1;
        this.updateNetStatus(device)
      }
      this.updateBleConnectState({ device, state: undefined, connectSuccess: isSuccess });
      return res;
    } else {
      return { success: false, message: i18n.t("NOT_FOUND_DEVICE") };
    }
  }

  @action.bound
  async disconnectBleDevice(device: IDevice) {
    console.log("蓝牙断开", device);
    this.updateBleConnectState({ device, state: ConnectState.disconnecting });
    const res = await SDK.disconnectBleDevice(device);
    console.log("蓝牙断开", res);
    if (res && res.success) {
      console.log("蓝牙断开成功");
      SDK.getDeviceStatus({ device })
    }
    this.updateBleConnectState({ device, state: undefined });
    return res;
  }

  // 由于小程序的订阅中字段与wifi不一致，所以在切换能力的时候，要用这个方法来切换连接方式
  @action.bound
  async disconnectFakeBleDevice(device: IDevice) {
    this.updateBleConnectState({ device, state: ConnectState.disconnecting });
    const res = await SDK.setSubscribe({ device, subscribed: true });
    console.log("蓝牙Fake断开", res);
    if (res && res.success) {
      console.log("蓝牙Fake断开成功");
      SDK.getDeviceStatus({ device })
    }
    this.updateBleConnectState({ device, state: undefined });
    return res;
  }

  @action
  cleanData() {
    this.data = [];
    this.sdkDeviceList = [];
    this.sdkBleDevices = [];
    this.serviceDeviceList = [];
  }

  deviceIsInUnbindMap(device: IDevice) {
    const deviceId = getDeviceId(device);
    return !!unbindDeviceMap[deviceId];
  }

}

// 检测设备是否需要连接
export const checkoutDeviceNeedConnect = (device: INewDevice) => {
  if (!device) {
    return;
  }
  if (deviceIsInConnecting(device)) {
    return;
  }
  // 检查是不是可控
  if (device.netStatus === 2) {
    return;
  }
  console.log('checkoutDeviceNeedConnect', device.bleCapacity);
  // 不可控的话，证明只有在线，准备中或者离线的状态，由于wifi是自动订阅的，这里只判断蓝牙是不是需要发起连接
  if (device.bleCapacity && device.bleCapacity.state === CapacityState.online && (
    !device.wifiCapacity
    || device.wifiCapacity.level <= device.bleCapacity.level
  )) {
    // 有蓝牙能力，但没有wifi能力，证明是纯蓝牙。或者是蓝牙能力优先级高于wifi，都可以发起蓝牙连接
    if (!deviceListModel.deviceIsInUnbindMap(device)) {
      deviceListModel.connectBleDevice(device);
    }
  }
}

const checkListIsEqual = (a: any, b: any) => {
  // console.log('checkListIsEqual', toJS(a), toJS(b));
  if (a.length !== b.length) {
    return false;
  }
  for (let i = 0; i < b.length; i++) {
    if (a[i] !== b[i]) {
      return false;
    }
  }
  return true;
};

const deviceListModel = new DeviceList();

const checkSubscribe = (newDeviceListData: any, firstRun: boolean) => {
  if (newDeviceListData.length === 0) return;
  // 蓝牙设备不主动订阅
  newDeviceListData.map((item: any) => {
    const product = getItemForPk(item.productKey)
    if (product && isBLE(product)) {
      return;
    }

    deviceListModel.setDeviceSubscribe(item, firstRun);
  });
};

let firstRun = true;
reaction(
  () => toJS(deviceListModel.data),
  (deviceListData: IDevice[]) => {
    // 检查订阅
    // console.log("reaction");
    if (global.token) {
      const needList = deviceListData.filter(i => i.connectType === 'NONE' && !isBLEBroadCast(getItemForPk(i.productKey)) && !deviceIsInConnecting(i));
      // console.log("自动订阅设备列表", needList);
      checkSubscribe(needList, firstRun);
      if (firstRun) {
        firstRun = false;
      }
      if (deviceDetailModel.device && !deviceDetailModel.device.isVirtual) {
        const d = deviceListData.find((i) =>
          isSameDevice(i, deviceDetailModel.device)
        );
        if (d) {
          console.log("d", d);
          if (!isEqual(d, deviceDetailModel.device)) {
            // 这里可以做模板的一些自动操作
            // console.log("reaction update");
            deviceDetailModel.updateDeviceDetail(d);
            // 如果是蓝牙能力需要连接的设备，自动发起蓝牙连接
            checkoutDeviceNeedConnect(d as INewDevice);
          }
        } else {
          // 退出模板页面
          deviceDataModel.allBackToHome();
        }
      }
    }
  },
  {
    fireImmediately: true,
    delay: 800,
    equals: checkListIsEqual,
  }
);

const DeviceList_Store_Key = "deviceList";

export { DeviceList, DeviceList_Store_Key };
export { checkListIsEqual };

export default deviceListModel;
